home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue68 / Alfresco / AAChrStm.pas next >
Encoding:
Pascal/Delphi Source File  |  2001-02-16  |  8.2 KB  |  294 lines

  1. unit AAChrStm;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils,
  7.   Classes;
  8.  
  9. type
  10.   TaaInCharStream = class(TStream)
  11.     private
  12.       FBufEnd : integer;
  13.       FBuffer : PByteArray;
  14.       FBufPos : integer;
  15.       FStream : TStream;
  16.       FPutBackBuf : array [0..1] of char;
  17.       FPutBackInx : integer;
  18.     protected
  19.       procedure icsGetBuffer;
  20.     public
  21.       constructor Create(aStream : TStream);
  22.       destructor Destroy; override;
  23.  
  24.       function Read(var Buffer; Count : longint) : longint; override;
  25.       function Write(const Buffer; Count : longint) : longint; override;
  26.       function Seek(Offset : longint; Origin : word) : longint; override;
  27.  
  28.       function GetChar : char;
  29.       procedure PutBackChar(aCh : char);
  30.   end;
  31.  
  32.   TaaEndOfLine = (eolCRLF, eolLF);
  33.  
  34.   TaaOutCharStream = class(TStream)
  35.     private
  36.       FBuffer : PByteArray;
  37.       FBufPos : integer;
  38.       FEOL    : TaaEndOfLine;
  39.       FStream : TStream;
  40.     protected
  41.       procedure ocsFlush;
  42.     public
  43.       constructor Create(aStream : TStream);
  44.       destructor Destroy; override;
  45.  
  46.       function Read(var Buffer; Count : longint) : longint; override;
  47.       function Write(const Buffer; Count : longint) : longint; override;
  48.       function Seek(Offset : longint; Origin : word) : longint; override;
  49.  
  50.       procedure PutChar(aCh : char);
  51.  
  52.       property EndOfLine : TaaEndOfLine read FEOL write FEOL;
  53.   end;
  54.  
  55. implementation
  56.  
  57. const
  58.   BufSize = 8192;
  59.   CR      = #13;
  60.   LF      = #10;
  61.  
  62. {===TaaInCharStream==================================================}
  63. constructor TaaInCharStream.Create(aStream : TStream);
  64. begin
  65.   {create the ancestor}
  66.   inherited Create;
  67.   {save the stream}
  68.   FStream := aStream;
  69.   {create the buffer}
  70.   GetMem(FBuffer, BufSize);
  71.  {FBufPos := 0;}
  72.  {FBufEnd := 0;}
  73. end;
  74. {--------}
  75. destructor TaaInCharStream.Destroy;
  76. begin
  77.   if (FBuffer <> nil) then
  78.     FreeMem(FBuffer, BufSize);
  79. end;
  80. {--------}
  81. function TaaInCharStream.GetChar : char;
  82. begin
  83.   repeat
  84.     {use putback chars if available}
  85.     if (FPutBackInx <> 0) then begin
  86.       dec(FPutBackInx);
  87.       Result := FPutBackBuf[FPutBackInx];
  88.     end
  89.     {otherwise use the buffer}
  90.     else begin
  91.       {make sure the buffer has data}
  92.       if (FBufPos = FBufEnd) then
  93.         icsGetBuffer;
  94.       {if there is no more data, return #0 to signal end of stream}
  95.       if (FBufEnd = 0) then
  96.         Result := #0
  97.       {otherwise return the current character}
  98.       else begin
  99.         Result := char(FBuffer^[FBufPos]);
  100.         Assert(Result <> #0,
  101.                'TaaInCharStream.GetChar: input stream is not text, read null');
  102.         inc(FBufPos);
  103.       end;
  104.     end;
  105.   until (Result <> CR);
  106. end;
  107. {--------}
  108. procedure TaaInCharStream.icsGetBuffer;
  109. begin
  110.   FBufPos := 0;
  111.   FBufEnd := FStream.Read(FBuffer^, BufSize);
  112. end;
  113. {--------}
  114. procedure TaaInCharStream.PutBackChar(aCh : char);
  115. begin
  116.   Assert(FPutBackInx < 2,
  117.          'TaaInCharStream.PutBackChar: put back buffer is full');
  118.   FPutBackBuf[FPutBackInx] := aCh;
  119.   inc(FPutBackInx);
  120. end;
  121. {--------}
  122. function TaaInCharStream.Read(var Buffer; Count : longint) : longint;
  123. var
  124.   BytesToRead : longint;
  125.   OutBuf       : PByteArray;
  126.   OutBufPos    : integer;
  127. begin
  128.   {make sure the buffer has data}
  129.   if (FBufPos = FBufEnd) then
  130.     icsGetBuffer;
  131.   {assume we read nothing}
  132.   Result := 0;
  133.   if (FBufEnd = 0) then
  134.     Exit;
  135.   {calculate the number of bytes to copy the first time}
  136.   BytesToRead := FBufEnd - FBufPos;
  137.   if (Count < BytesToRead) then
  138.     BytesToRead := Count;
  139.   {copy the calculated number of bytes}
  140.   Move(FBuffer^[FBufPos], Buffer, BytesToRead);
  141.   inc(FBufPos, BytesToRead);
  142.   dec(Count, BytesToRead);
  143.   inc(Result, BytesToRead);
  144.   {if there are still bytes to copy, do so}
  145.   if (Count <> 0) then begin
  146.     {create indexable pointer to output buffer}
  147.     OutBuf := PByteArray(@Buffer);
  148.     OutBufPos := BytesToRead;
  149.     {while there are bytes to copy...}
  150.     while (Count <> 0) do begin
  151.       {read from the underlying stream}
  152.       icsGetBuffer;
  153.       if (FBufEnd = 0) then
  154.         Exit;
  155.       {calculate the number of bytes to copy this time}
  156.       BytesToRead := FBufEnd;
  157.       if (Count < BytesToRead) then
  158.         BytesToRead := Count;
  159.       {copy the calculated number of bytes}
  160.       Move(FBuffer^[FBufPos], OutBuf^[OutBufPos], BytesToRead);
  161.       inc(FBufPos, BytesToRead);
  162.       inc(OutBufPos, BytesToRead);
  163.       dec(Count, BytesToRead);
  164.       inc(Result, BytesToRead);
  165.     end;
  166.   end;
  167. end;
  168. {--------}
  169. function TaaInCharStream.Seek(Offset : longint; Origin : word) : longint;
  170. begin
  171.   Assert(false,
  172.          'TaaOutCharStream.Seek: this class is write only, it cannot seek');
  173.   Result := 0; {to satify the compiler}
  174. end;
  175. {--------}
  176. function TaaInCharStream.Write(const Buffer; Count : longint) : longint;
  177. begin
  178.   Assert(false,
  179.          'TaaInCharStream.Write: this class is read only, it cannot write');
  180.   Result := 0; {to satisfy the compiler}
  181. end;
  182. {====================================================================}
  183.  
  184.  
  185. {===TaaOutCharStream=================================================}
  186. constructor TaaOutCharStream.Create(aStream : TStream);
  187. begin
  188.   {create the ancestor}
  189.   inherited Create;
  190.   {save the stream}
  191.   FStream := aStream;
  192.   {create the buffer}
  193.   GetMem(FBuffer, BufSize);
  194.  {FBufPos := 0;}
  195. end;
  196. {--------}
  197. destructor TaaOutCharStream.Destroy;
  198. begin
  199.   {if there is a buffer and there is some data, flush it,
  200.    then free the buffer}
  201.   if (FBuffer <> nil) then begin
  202.     ocsFlush;
  203.     FreeMem(FBuffer, BufSize);
  204.   end;
  205.   {free the ancestor}
  206.   inherited Destroy;
  207. end;
  208. {--------}
  209. procedure TaaOutCharStream.ocsFlush;
  210. begin
  211.   {if there's data in the buffer, write it to the underlying stream}
  212.   if (FBufPos <> 0) then begin
  213.     FStream.WriteBuffer(FBuffer^, FBufPos);
  214.     FBufPos := 0;
  215.   end;
  216. end;
  217. {--------}
  218. procedure TaaOutCharStream.PutChar(aCh : char);
  219. begin
  220.   if (FEOL = eolCRLF) and (aCh = LF) then begin
  221.     {add a CR to the buffer}
  222.     FBuffer^[FBufPos] := byte(CR);
  223.     inc(FBufPos);
  224.     {if the buffer is full, flush it to the underlying stream}
  225.     if (FBufPos = BufSize) then
  226.       ocsFlush;
  227.   end;
  228.   {add the character to the buffer}
  229.   FBuffer^[FBufPos] := byte(aCh);
  230.   inc(FBufPos);
  231.   {if the buffer is full, flush it to the underlying stream}
  232.   if (FBufPos = BufSize) then
  233.     ocsFlush;
  234. end;
  235. {--------}
  236. function TaaOutCharStream.Read(var Buffer; Count : longint) : longint;
  237. begin
  238.   Assert(false,
  239.          'TaaOutCharStream.Read: this class is write only, it cannot read');
  240.   Result := 0; {to satisfy the compiler}
  241. end;
  242. {--------}
  243. function TaaOutCharStream.Seek(Offset : longint; Origin : word) : longint;
  244. begin
  245.   Assert(false,
  246.          'TaaOutCharStream.Seek: this class is write only, it cannot seek');
  247.   Result := 0; {to satisfy the compiler}
  248. end;
  249. {--------}
  250. function TaaOutCharStream.Write(const Buffer; Count : longint) : longint;
  251. var
  252.   BytesToWrite : longint;
  253.   InBuf        : PByteArray;
  254.   InBufPos     : integer;
  255. begin
  256.   {assume we write the entire buffer}
  257.   Result := Count;
  258.   {calculate the number of bytes to copy the first time}
  259.   BytesToWrite := BufSize - FBufPos;
  260.   if (Count < BytesToWrite) then
  261.     BytesToWrite := Count;
  262.   {copy the calculated number of bytes}
  263.   Move(Buffer, FBuffer^[FBufPos], BytesToWrite);
  264.   inc(FBufPos, BytesToWrite);
  265.   dec(Count, BytesToWrite);
  266.   {if there are still bytes to copy, do so}
  267.   if (Count <> 0) then begin
  268.     {create indexable pointer to input buffer}
  269.     InBuf := PByteArray(@Buffer);
  270.     InBufPos := BytesToWrite;
  271.     {while there are bytes to copy...}
  272.     while (Count <> 0) do begin
  273.       {flush the output buffer}
  274.       ocsFlush;
  275.      {calculate the number of bytes to copy this time}
  276.       BytesToWrite := BufSize;
  277.       if (Count < BytesToWrite) then
  278.         BytesToWrite := Count;
  279.       {copy the calculated number of bytes}
  280.       Move(InBuf^[InBufPos], FBuffer^[FBufPos], BytesToWrite);
  281.       inc(FBufPos, BytesToWrite);
  282.       inc(InBufPos, BytesToWrite);
  283.       dec(Count, BytesToWrite);
  284.     end;
  285.   end;
  286.   {if the buffer is full, flush it to the underlying stream}
  287.   if (FBufPos = BufSize) then
  288.     ocsFlush;
  289. end;
  290. {====================================================================}
  291.  
  292.  
  293. end.
  294.